import {TiledMap, Vec2, Vec3} from 'cc';
import {SceneManager} from "db://assets/script/modules/SceneManager";


type MapLayerDataType = {
    noCross?: boolean
    gateway?: boolean
    gatewayTarget?: string
    territory?: boolean
    territoryName?: string
}

export class GridSystemManage {
    public static readonly gridSize: number = 64; // 网格单位尺寸
    public static mapLayerData: MapLayerDataType[][] = []; // 地图数据
    public static tiledMap: TiledMap

    /**
     * 初始化网格
     * @param tiledMap
     */
    public static initGrid(tiledMap: TiledMap) {
        this.tiledMap = tiledMap;
        const {width: gridCols, height: gridRows} = tiledMap.getMapSize();
        const {width: sizeWidth, height: sizeHeight} = tiledMap.getTileSize();
        // console.log(sizeWidth * gridCols, sizeHeight * gridRows)

        // 理论上计算为结果必为整数
        const calcX = sizeWidth * gridCols / this.gridSize
        const calcY = sizeHeight * gridRows / this.gridSize

        // 初始化二维数组
        this.mapLayerData = Array.from({length: calcX}, () =>
            Array.from({length: calcY}, () => ({} as MapLayerDataType))
        );

        // 初始化领地数据
        const territoryData = {};

        // 合并图层处理逻辑
        const layers = this.tiledMap.getLayers();
        layers.forEach(layer => {
            const layerTypes: MapLayerDataType = {
                gateway: Boolean(layer.getProperty('gateway')),
                noCross: Boolean(layer.getProperty('noCross')),
                territory: Boolean(layer.getProperty('territory'))
            };

            // 跳过无需处理的图层
            if (Object.keys(layerTypes).every(key => !layerTypes[key])) return;

            // 预计算图层属性值
            const gatewayTarget = layerTypes.gateway ? layer.getProperty('gatewayTarget') as string : "";
            const territoryName = layerTypes.territory ? layer.getProperty('territoryName') as string : "";

            // 初始化领地存储
            if (layerTypes.territory) {
                territoryData[territoryName] = [];
            }

            // 统一处理坐标计算
            for (let x = 0; x < calcX; x++) {
                for (let y = 0; y < calcY; y++) {
                    // 复用计算结果
                    const gridCol = Math.floor(x * this.gridSize / sizeWidth);
                    const gridRow = Math.floor(y * this.gridSize / sizeHeight);

                    if (layer.getTileGIDAt(gridCol, gridRow) === 0) continue;

                    // 批量设置属性
                    if (layerTypes.territory) {
                        this.mapLayerData[x][y].territory = true;
                        this.mapLayerData[x][y].territoryName = territoryName;
                        territoryData[territoryName].push(new Vec2(x, y));
                    }
                    if (layerTypes.gateway) {
                        this.mapLayerData[x][y].gateway = true;
                        this.mapLayerData[x][y].gatewayTarget = gatewayTarget;
                    }
                    if (layerTypes.noCross) {
                        this.mapLayerData[x][y].noCross = true;
                    }
                }
            }
        });

        // 把领地数据存储起来
        SceneManager.setTerritoryData(territoryData)

    }

    /**
     * ⭐ui坐标转换网格坐标 锚点左上角
     * @param worldPos
     */
    public static nodePosToGridPos(worldPos: Vec3 | Vec2): Vec2 {
        return new Vec2(
            Math.ceil(worldPos.x / this.gridSize),
            Math.ceil(-worldPos.y / this.gridSize),
        );
    }

    /**
     * ⭐网格坐标转换ui坐标 锚点左上角
     * @param gridPos
     */
    public static gridPosToNodePos(gridPos: Vec2): Vec3 {
        return new Vec3(
            gridPos.x * this.gridSize,
            -gridPos.y * this.gridSize,
        );
    }

    /**
     * 检查目标位置是否合法-安全
     * @param gridPos
     */
    public static checkTargetIsValid(gridPos: Vec2) {
        return !this.checkTargetIsGateway(gridPos) && !this.checkTargetIsNoCross(gridPos) && !this.checkTargetIsMargin(gridPos);
    }

    /**
     * 检查目标位置是否到达边界
     * @param gridPos
     */
    public static checkTargetIsMargin(gridPos: Vec2): boolean {
        if (!this.mapLayerData.length) return true
        return !(gridPos.x in this.mapLayerData) || !(gridPos.y in this.mapLayerData[0])
    }

    /**
     * 检查目标位置是否有障碍物
     * @param gridPos
     */
    public static checkTargetIsNoCross(gridPos: Vec2): boolean {
        return this.mapLayerData[gridPos.x][gridPos.y].noCross
    }

    /**
     * 检查目标位置是否有传送
     * @param gridPos
     */
    public static checkTargetIsGateway(gridPos: Vec2): boolean {
        return this.mapLayerData[gridPos.x][gridPos.y].gateway
    }

    /**
     * 获取传送地图
     * @param gridPos
     */
    public static getGatewayTarget(gridPos: Vec2): string {
        return this.mapLayerData[gridPos.x][gridPos.y].gatewayTarget || ''
    }

    /**
     * ⭐A*寻路算法实现
     * @param start
     * @param end
     */
    public static findPath(start: Vec2, end: Vec2): Vec2[] {
        class Path {
            constructor(
                public x: number,
                public y: number,
                public parent: Path | null = null,
                public g: number = 0,
                public h: number = 0
            ) {
            }

            get f() {
                return this.g + this.h;
            }
        }

        const openList: Path[] = [];
        const closedList: Set<string> = new Set();

        // 起点终点取整
        const startX = Math.round(start.x);
        const startY = Math.round(start.y);
        const endX = Math.round(end.x);
        const endY = Math.round(end.y);

        openList.push(new Path(startX, startY));

        while (openList.length > 0) {
            // 获取最低F值的节点
            let currentPath = openList.reduce((prev, curr) => prev.f < curr.f ? prev : curr);

            // 到达终点
            if (currentPath.x === endX && currentPath.y === endY) {
                const path: Vec2[] = [];
                while (currentPath) {
                    path.push(new Vec2(currentPath.x, currentPath.y));
                    currentPath = currentPath.parent!;
                }
                return path.reverse();
            }

            // 移动当前节点到关闭列表
            openList.splice(openList.indexOf(currentPath), 1);
            closedList.add(`${currentPath.x},${currentPath.y}`);

            // 遍历相邻节点
            const neighbors = [
                {dx: 1, dy: 0}, {dx: -1, dy: 0},
                {dx: 0, dy: 1}, {dx: 0, dy: -1}
            ];

            for (const dir of neighbors) {
                const x = currentPath.x + dir.dx;
                const y = currentPath.y + dir.dy;

                // 边界检查
                if (this.checkTargetIsMargin(new Vec2(x, y))) {
                    continue;
                }
                // 障碍检查
                if (this.checkTargetIsNoCross(new Vec2(x, y))) {
                    continue;
                }

                // 跳过已关闭节点
                if (closedList.has(`${x},${y}`)) continue;

                // 计算代价值
                const g = currentPath.g + 1;
                const h = Math.abs(x - endX) + Math.abs(y - endY);

                // 查找开放列表中的节点
                let neighborPath = openList.find(n => n.x === x && n.y === y);

                if (!neighborPath) {
                    neighborPath = new Path(x, y, currentPath, g, h);
                    openList.push(neighborPath);
                } else if (g < neighborPath.g) {
                    neighborPath.parent = currentPath;
                    neighborPath.g = g;
                    neighborPath.h = h;
                }
            }
        }

        return []; // 无可用路径
    }

    generateMonsterGridPos() {
    }
}
